1
|
|
|
/** |
2
|
|
|
* Perform a jQuery selector action on the table's TR elements (from the tbody) and |
3
|
|
|
* return the resulting jQuery object. |
4
|
|
|
* @param {string|node|jQuery} sSelector jQuery selector or node collection to act on |
5
|
|
|
* @param {object} [oOpts] Optional parameters for modifying the rows to be included |
6
|
|
|
* @param {string} [oOpts.filter=none] Select TR elements that meet the current filter |
7
|
|
|
* criterion ("applied") or all TR elements (i.e. no filter). |
8
|
|
|
* @param {string} [oOpts.order=current] Order of the TR elements in the processed array. |
9
|
|
|
* Can be either 'current', whereby the current sorting of the table is used, or |
10
|
|
|
* 'original' whereby the original order the data was read into the table is used. |
11
|
|
|
* @param {string} [oOpts.page=all] Limit the selection to the currently displayed page |
12
|
|
|
* ("current") or not ("all"). If 'current' is given, then order is assumed to be |
13
|
|
|
* 'current' and filter is 'applied', regardless of what they might be given as. |
14
|
|
|
* @returns {object} jQuery object, filtered by the given selector. |
15
|
|
|
* @dtopt API |
16
|
|
|
* |
17
|
|
|
* @example |
18
|
|
|
* $(document).ready(function() { |
19
|
|
|
* var oTable = $('#example').dataTable(); |
20
|
|
|
* |
21
|
|
|
* // Highlight every second row |
22
|
|
|
* oTable.$('tr:odd').css('backgroundColor', 'blue'); |
23
|
|
|
* } ); |
24
|
|
|
* |
25
|
|
|
* @example |
26
|
|
|
* $(document).ready(function() { |
27
|
|
|
* var oTable = $('#example').dataTable(); |
28
|
|
|
* |
29
|
|
|
* // Filter to rows with 'Webkit' in them, add a background colour and then |
30
|
|
|
* // remove the filter, thus highlighting the 'Webkit' rows only. |
31
|
|
|
* oTable.fnFilter('Webkit'); |
32
|
|
|
* oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue'); |
33
|
|
|
* oTable.fnFilter(''); |
34
|
|
|
* } ); |
35
|
|
|
*/ |
36
|
|
|
this.$ = function ( sSelector, oOpts ) |
37
|
|
|
{ |
38
|
|
|
var i, iLen, a = [], tr; |
39
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
40
|
|
|
var aoData = oSettings.aoData; |
41
|
|
|
var aiDisplay = oSettings.aiDisplay; |
42
|
|
|
var aiDisplayMaster = oSettings.aiDisplayMaster; |
43
|
|
|
|
44
|
|
|
if ( !oOpts ) |
45
|
|
|
{ |
46
|
|
|
oOpts = {}; |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
oOpts = $.extend( {}, { |
50
|
|
|
"filter": "none", // applied |
51
|
|
|
"order": "current", // "original" |
52
|
|
|
"page": "all" // current |
53
|
|
|
}, oOpts ); |
54
|
|
|
|
55
|
|
|
// Current page implies that order=current and fitler=applied, since it is fairly |
56
|
|
|
// senseless otherwise |
57
|
|
|
if ( oOpts.page == 'current' ) |
58
|
|
|
{ |
59
|
|
|
for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ ) |
60
|
|
|
{ |
61
|
|
|
tr = aoData[ aiDisplay[i] ].nTr; |
62
|
|
|
if ( tr ) |
63
|
|
|
{ |
64
|
|
|
a.push( tr ); |
65
|
|
|
} |
66
|
|
|
} |
67
|
|
|
} |
68
|
|
|
else if ( oOpts.order == "current" && oOpts.filter == "none" ) |
69
|
|
|
{ |
70
|
|
|
for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ ) |
71
|
|
|
{ |
72
|
|
|
tr = aoData[ aiDisplayMaster[i] ].nTr; |
73
|
|
|
if ( tr ) |
74
|
|
|
{ |
75
|
|
|
a.push( tr ); |
76
|
|
|
} |
77
|
|
|
} |
78
|
|
|
} |
79
|
|
|
else if ( oOpts.order == "current" && oOpts.filter == "applied" ) |
80
|
|
|
{ |
81
|
|
|
for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ ) |
82
|
|
|
{ |
83
|
|
|
tr = aoData[ aiDisplay[i] ].nTr; |
84
|
|
|
if ( tr ) |
85
|
|
|
{ |
86
|
|
|
a.push( tr ); |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
} |
90
|
|
|
else if ( oOpts.order == "original" && oOpts.filter == "none" ) |
91
|
|
|
{ |
92
|
|
|
for ( i=0, iLen=aoData.length ; i<iLen ; i++ ) |
93
|
|
|
{ |
94
|
|
|
tr = aoData[ i ].nTr ; |
95
|
|
|
if ( tr ) |
96
|
|
|
{ |
97
|
|
|
a.push( tr ); |
98
|
|
|
} |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
else if ( oOpts.order == "original" && oOpts.filter == "applied" ) |
102
|
|
|
{ |
103
|
|
|
for ( i=0, iLen=aoData.length ; i<iLen ; i++ ) |
104
|
|
|
{ |
105
|
|
|
tr = aoData[ i ].nTr; |
106
|
|
|
if ( $.inArray( i, aiDisplay ) !== -1 && tr ) |
107
|
|
|
{ |
108
|
|
|
a.push( tr ); |
109
|
|
|
} |
110
|
|
|
} |
111
|
|
|
} |
112
|
|
|
else |
113
|
|
|
{ |
114
|
|
|
_fnLog( oSettings, 1, "Unknown selection options" ); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/* We need to filter on the TR elements and also 'find' in their descendants |
118
|
|
|
* to make the selector act like it would in a full table - so we need |
119
|
|
|
* to build both results and then combine them together |
120
|
|
|
*/ |
121
|
|
|
var jqA = $(a); |
122
|
|
|
var jqTRs = jqA.filter( sSelector ); |
123
|
|
|
var jqDescendants = jqA.find( sSelector ); |
124
|
|
|
|
125
|
|
|
return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) ); |
126
|
|
|
}; |
127
|
|
|
|
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Almost identical to $ in operation, but in this case returns the data for the matched |
131
|
|
|
* rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes |
132
|
|
|
* rather than any descendants, so the data can be obtained for the row/cell. If matching |
133
|
|
|
* rows are found, the data returned is the original data array/object that was used to |
134
|
|
|
* create the row (or a generated array if from a DOM source). |
135
|
|
|
* |
136
|
|
|
* This method is often useful in-combination with $ where both functions are given the |
137
|
|
|
* same parameters and the array indexes will match identically. |
138
|
|
|
* @param {string|node|jQuery} sSelector jQuery selector or node collection to act on |
139
|
|
|
* @param {object} [oOpts] Optional parameters for modifying the rows to be included |
140
|
|
|
* @param {string} [oOpts.filter=none] Select elements that meet the current filter |
141
|
|
|
* criterion ("applied") or all elements (i.e. no filter). |
142
|
|
|
* @param {string} [oOpts.order=current] Order of the data in the processed array. |
143
|
|
|
* Can be either 'current', whereby the current sorting of the table is used, or |
144
|
|
|
* 'original' whereby the original order the data was read into the table is used. |
145
|
|
|
* @param {string} [oOpts.page=all] Limit the selection to the currently displayed page |
146
|
|
|
* ("current") or not ("all"). If 'current' is given, then order is assumed to be |
147
|
|
|
* 'current' and filter is 'applied', regardless of what they might be given as. |
148
|
|
|
* @returns {array} Data for the matched elements. If any elements, as a result of the |
149
|
|
|
* selector, were not TR, TD or TH elements in the DataTable, they will have a null |
150
|
|
|
* entry in the array. |
151
|
|
|
* @dtopt API |
152
|
|
|
* |
153
|
|
|
* @example |
154
|
|
|
* $(document).ready(function() { |
155
|
|
|
* var oTable = $('#example').dataTable(); |
156
|
|
|
* |
157
|
|
|
* // Get the data from the first row in the table |
158
|
|
|
* var data = oTable._('tr:first'); |
159
|
|
|
* |
160
|
|
|
* // Do something useful with the data |
161
|
|
|
* alert( "First cell is: "+data[0] ); |
162
|
|
|
* } ); |
163
|
|
|
* |
164
|
|
|
* @example |
165
|
|
|
* $(document).ready(function() { |
166
|
|
|
* var oTable = $('#example').dataTable(); |
167
|
|
|
* |
168
|
|
|
* // Filter to 'Webkit' and get all data for |
169
|
|
|
* oTable.fnFilter('Webkit'); |
170
|
|
|
* var data = oTable._('tr', {"filter": "applied"}); |
171
|
|
|
* |
172
|
|
|
* // Do something with the data |
173
|
|
|
* alert( data.length+" rows matched the filter" ); |
174
|
|
|
* } ); |
175
|
|
|
*/ |
176
|
|
|
this._ = function ( sSelector, oOpts ) |
177
|
|
|
{ |
178
|
|
|
var aOut = []; |
179
|
|
|
var i, iLen, iIndex; |
|
|
|
|
180
|
|
|
var aTrs = this.$( sSelector, oOpts ); |
181
|
|
|
|
182
|
|
|
for ( i=0, iLen=aTrs.length ; i<iLen ; i++ ) |
183
|
|
|
{ |
184
|
|
|
aOut.push( this.fnGetData(aTrs[i]) ); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
return aOut; |
188
|
|
|
}; |
189
|
|
|
|
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Add a single new row or multiple rows of data to the table. Please note |
193
|
|
|
* that this is suitable for client-side processing only - if you are using |
194
|
|
|
* server-side processing (i.e. "bServerSide": true), then to add data, you |
195
|
|
|
* must add it to the data source, i.e. the server-side, through an Ajax call. |
196
|
|
|
* @param {array|object} mData The data to be added to the table. This can be: |
197
|
|
|
* <ul> |
198
|
|
|
* <li>1D array of data - add a single row with the data provided</li> |
199
|
|
|
* <li>2D array of arrays - add multiple rows in a single call</li> |
200
|
|
|
* <li>object - data object when using <i>mData</i></li> |
201
|
|
|
* <li>array of objects - multiple data objects when using <i>mData</i></li> |
202
|
|
|
* </ul> |
203
|
|
|
* @param {bool} [bRedraw=true] redraw the table or not |
204
|
|
|
* @returns {array} An array of integers, representing the list of indexes in |
205
|
|
|
* <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to |
206
|
|
|
* the table. |
207
|
|
|
* @dtopt API |
208
|
|
|
* |
209
|
|
|
* @example |
210
|
|
|
* // Global var for counter |
211
|
|
|
* var giCount = 2; |
212
|
|
|
* |
213
|
|
|
* $(document).ready(function() { |
214
|
|
|
* $('#example').dataTable(); |
215
|
|
|
* } ); |
216
|
|
|
* |
217
|
|
|
* function fnClickAddRow() { |
218
|
|
|
* $('#example').dataTable().fnAddData( [ |
219
|
|
|
* giCount+".1", |
220
|
|
|
* giCount+".2", |
221
|
|
|
* giCount+".3", |
222
|
|
|
* giCount+".4" ] |
223
|
|
|
* ); |
224
|
|
|
* |
225
|
|
|
* giCount++; |
226
|
|
|
* } |
227
|
|
|
*/ |
228
|
|
|
this.fnAddData = function( mData, bRedraw ) |
229
|
|
|
{ |
230
|
|
|
if ( mData.length === 0 ) |
231
|
|
|
{ |
232
|
|
|
return []; |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
var aiReturn = []; |
236
|
|
|
var iTest; |
237
|
|
|
|
238
|
|
|
/* Find settings from table node */ |
239
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
240
|
|
|
|
241
|
|
|
/* Check if we want to add multiple rows or not */ |
242
|
|
|
if ( typeof mData[0] === "object" && mData[0] !== null ) |
243
|
|
|
{ |
244
|
|
|
for ( var i=0 ; i<mData.length ; i++ ) |
245
|
|
|
{ |
246
|
|
|
iTest = _fnAddData( oSettings, mData[i] ); |
247
|
|
|
if ( iTest == -1 ) |
248
|
|
|
{ |
249
|
|
|
return aiReturn; |
250
|
|
|
} |
251
|
|
|
aiReturn.push( iTest ); |
252
|
|
|
} |
253
|
|
|
} |
254
|
|
|
else |
255
|
|
|
{ |
256
|
|
|
iTest = _fnAddData( oSettings, mData ); |
257
|
|
|
if ( iTest == -1 ) |
258
|
|
|
{ |
259
|
|
|
return aiReturn; |
260
|
|
|
} |
261
|
|
|
aiReturn.push( iTest ); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); |
265
|
|
|
|
266
|
|
|
if ( bRedraw === undefined || bRedraw ) |
267
|
|
|
{ |
268
|
|
|
_fnReDraw( oSettings ); |
269
|
|
|
} |
270
|
|
|
return aiReturn; |
271
|
|
|
}; |
272
|
|
|
|
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* This function will make DataTables recalculate the column sizes, based on the data |
276
|
|
|
* contained in the table and the sizes applied to the columns (in the DOM, CSS or |
277
|
|
|
* through the sWidth parameter). This can be useful when the width of the table's |
278
|
|
|
* parent element changes (for example a window resize). |
279
|
|
|
* @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to |
280
|
|
|
* @dtopt API |
281
|
|
|
* |
282
|
|
|
* @example |
283
|
|
|
* $(document).ready(function() { |
284
|
|
|
* var oTable = $('#example').dataTable( { |
285
|
|
|
* "sScrollY": "200px", |
286
|
|
|
* "bPaginate": false |
287
|
|
|
* } ); |
288
|
|
|
* |
289
|
|
|
* $(window).bind('resize', function () { |
290
|
|
|
* oTable.fnAdjustColumnSizing(); |
291
|
|
|
* } ); |
292
|
|
|
* } ); |
293
|
|
|
*/ |
294
|
|
|
this.fnAdjustColumnSizing = function ( bRedraw ) |
295
|
|
|
{ |
296
|
|
|
var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); |
297
|
|
|
_fnAdjustColumnSizing( oSettings ); |
298
|
|
|
|
299
|
|
|
if ( bRedraw === undefined || bRedraw ) |
300
|
|
|
{ |
301
|
|
|
this.fnDraw( false ); |
302
|
|
|
} |
303
|
|
|
else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" ) |
304
|
|
|
{ |
305
|
|
|
/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ |
306
|
|
|
this.oApi._fnScrollDraw(oSettings); |
307
|
|
|
} |
308
|
|
|
}; |
309
|
|
|
|
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* Quickly and simply clear a table |
313
|
|
|
* @param {bool} [bRedraw=true] redraw the table or not |
314
|
|
|
* @dtopt API |
315
|
|
|
* |
316
|
|
|
* @example |
317
|
|
|
* $(document).ready(function() { |
318
|
|
|
* var oTable = $('#example').dataTable(); |
319
|
|
|
* |
320
|
|
|
* // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) |
321
|
|
|
* oTable.fnClearTable(); |
322
|
|
|
* } ); |
323
|
|
|
*/ |
324
|
|
|
this.fnClearTable = function( bRedraw ) |
325
|
|
|
{ |
326
|
|
|
/* Find settings from table node */ |
327
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
328
|
|
|
_fnClearTable( oSettings ); |
329
|
|
|
|
330
|
|
|
if ( bRedraw === undefined || bRedraw ) |
331
|
|
|
{ |
332
|
|
|
_fnDraw( oSettings ); |
333
|
|
|
} |
334
|
|
|
}; |
335
|
|
|
|
336
|
|
|
|
337
|
|
|
/** |
338
|
|
|
* The exact opposite of 'opening' a row, this function will close any rows which |
339
|
|
|
* are currently 'open'. |
340
|
|
|
* @param {node} nTr the table row to 'close' |
341
|
|
|
* @returns {int} 0 on success, or 1 if failed (can't find the row) |
342
|
|
|
* @dtopt API |
343
|
|
|
* |
344
|
|
|
* @example |
345
|
|
|
* $(document).ready(function() { |
346
|
|
|
* var oTable; |
347
|
|
|
* |
348
|
|
|
* // 'open' an information row when a row is clicked on |
349
|
|
|
* $('#example tbody tr').click( function () { |
350
|
|
|
* if ( oTable.fnIsOpen(this) ) { |
351
|
|
|
* oTable.fnClose( this ); |
352
|
|
|
* } else { |
353
|
|
|
* oTable.fnOpen( this, "Temporary row opened", "info_row" ); |
354
|
|
|
* } |
355
|
|
|
* } ); |
356
|
|
|
* |
357
|
|
|
* oTable = $('#example').dataTable(); |
358
|
|
|
* } ); |
359
|
|
|
*/ |
360
|
|
|
this.fnClose = function( nTr ) |
361
|
|
|
{ |
362
|
|
|
/* Find settings from table node */ |
363
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
364
|
|
|
|
365
|
|
|
for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ ) |
366
|
|
|
{ |
367
|
|
|
if ( oSettings.aoOpenRows[i].nParent == nTr ) |
368
|
|
|
{ |
369
|
|
|
var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode; |
370
|
|
|
if ( nTrParent ) |
371
|
|
|
{ |
372
|
|
|
/* Remove it if it is currently on display */ |
373
|
|
|
nTrParent.removeChild( oSettings.aoOpenRows[i].nTr ); |
374
|
|
|
} |
375
|
|
|
oSettings.aoOpenRows.splice( i, 1 ); |
376
|
|
|
return 0; |
377
|
|
|
} |
378
|
|
|
} |
379
|
|
|
return 1; |
380
|
|
|
}; |
381
|
|
|
|
382
|
|
|
|
383
|
|
|
/** |
384
|
|
|
* Remove a row for the table |
385
|
|
|
* @param {mixed} mTarget The index of the row from aoData to be deleted, or |
386
|
|
|
* the TR element you want to delete |
387
|
|
|
* @param {function|null} [fnCallBack] Callback function |
388
|
|
|
* @param {bool} [bRedraw=true] Redraw the table or not |
389
|
|
|
* @returns {array} The row that was deleted |
390
|
|
|
* @dtopt API |
391
|
|
|
* |
392
|
|
|
* @example |
393
|
|
|
* $(document).ready(function() { |
394
|
|
|
* var oTable = $('#example').dataTable(); |
395
|
|
|
* |
396
|
|
|
* // Immediately remove the first row |
397
|
|
|
* oTable.fnDeleteRow( 0 ); |
398
|
|
|
* } ); |
399
|
|
|
*/ |
400
|
|
|
this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw ) |
401
|
|
|
{ |
402
|
|
|
/* Find settings from table node */ |
403
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
404
|
|
|
var i, iLen, iAODataIndex; |
405
|
|
|
|
406
|
|
|
iAODataIndex = (typeof mTarget === 'object') ? |
407
|
|
|
_fnNodeToDataIndex(oSettings, mTarget) : mTarget; |
408
|
|
|
|
409
|
|
|
/* Return the data array from this row */ |
410
|
|
|
var oData = oSettings.aoData.splice( iAODataIndex, 1 ); |
411
|
|
|
|
412
|
|
|
/* Update the _DT_RowIndex parameter */ |
413
|
|
|
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) |
414
|
|
|
{ |
415
|
|
|
if ( oSettings.aoData[i].nTr !== null ) |
416
|
|
|
{ |
417
|
|
|
oSettings.aoData[i].nTr._DT_RowIndex = i; |
418
|
|
|
} |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
/* Remove the target row from the search array */ |
422
|
|
|
var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay ); |
423
|
|
|
oSettings.asDataSearch.splice( iDisplayIndex, 1 ); |
424
|
|
|
|
425
|
|
|
/* Delete from the display arrays */ |
426
|
|
|
_fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex ); |
427
|
|
|
_fnDeleteIndex( oSettings.aiDisplay, iAODataIndex ); |
428
|
|
|
|
429
|
|
|
/* If there is a user callback function - call it */ |
430
|
|
|
if ( typeof fnCallBack === "function" ) |
431
|
|
|
{ |
432
|
|
|
fnCallBack.call( this, oSettings, oData ); |
433
|
|
|
} |
434
|
|
|
|
435
|
|
|
/* Check for an 'overflow' they case for displaying the table */ |
436
|
|
|
if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() ) |
437
|
|
|
{ |
438
|
|
|
oSettings._iDisplayStart -= oSettings._iDisplayLength; |
439
|
|
|
if ( oSettings._iDisplayStart < 0 ) |
440
|
|
|
{ |
441
|
|
|
oSettings._iDisplayStart = 0; |
442
|
|
|
} |
443
|
|
|
} |
444
|
|
|
|
445
|
|
|
if ( bRedraw === undefined || bRedraw ) |
446
|
|
|
{ |
447
|
|
|
_fnCalculateEnd( oSettings ); |
448
|
|
|
_fnDraw( oSettings ); |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
return oData; |
452
|
|
|
}; |
453
|
|
|
|
454
|
|
|
|
455
|
|
|
/** |
456
|
|
|
* Restore the table to it's original state in the DOM by removing all of DataTables |
457
|
|
|
* enhancements, alterations to the DOM structure of the table and event listeners. |
458
|
|
|
* @param {boolean} [bRemove=false] Completely remove the table from the DOM |
459
|
|
|
* @dtopt API |
460
|
|
|
* |
461
|
|
|
* @example |
462
|
|
|
* $(document).ready(function() { |
463
|
|
|
* // This example is fairly pointless in reality, but shows how fnDestroy can be used |
464
|
|
|
* var oTable = $('#example').dataTable(); |
465
|
|
|
* oTable.fnDestroy(); |
466
|
|
|
* } ); |
467
|
|
|
*/ |
468
|
|
|
this.fnDestroy = function ( bRemove ) |
469
|
|
|
{ |
470
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
471
|
|
|
var nOrig = oSettings.nTableWrapper.parentNode; |
472
|
|
|
var nBody = oSettings.nTBody; |
473
|
|
|
var i, iLen; |
474
|
|
|
|
475
|
|
|
bRemove = (bRemove===undefined) ? false : bRemove; |
476
|
|
|
|
477
|
|
|
/* Flag to note that the table is currently being destroyed - no action should be taken */ |
478
|
|
|
oSettings.bDestroying = true; |
479
|
|
|
|
480
|
|
|
/* Fire off the destroy callbacks for plug-ins etc */ |
481
|
|
|
_fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] ); |
482
|
|
|
|
483
|
|
|
/* If the table is not being removed, restore the hidden columns */ |
484
|
|
|
if ( !bRemove ) |
485
|
|
|
{ |
486
|
|
|
for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) |
487
|
|
|
{ |
488
|
|
|
if ( oSettings.aoColumns[i].bVisible === false ) |
489
|
|
|
{ |
490
|
|
|
this.fnSetColumnVis( i, true ); |
491
|
|
|
} |
492
|
|
|
} |
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
/* Blitz all DT events */ |
496
|
|
|
$(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT'); |
497
|
|
|
|
498
|
|
|
/* If there is an 'empty' indicator row, remove it */ |
499
|
|
|
$('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove(); |
500
|
|
|
|
501
|
|
|
/* When scrolling we had to break the table up - restore it */ |
502
|
|
|
if ( oSettings.nTable != oSettings.nTHead.parentNode ) |
503
|
|
|
{ |
504
|
|
|
$(oSettings.nTable).children('thead').remove(); |
505
|
|
|
oSettings.nTable.appendChild( oSettings.nTHead ); |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode ) |
509
|
|
|
{ |
510
|
|
|
$(oSettings.nTable).children('tfoot').remove(); |
511
|
|
|
oSettings.nTable.appendChild( oSettings.nTFoot ); |
512
|
|
|
} |
513
|
|
|
|
514
|
|
|
/* Remove the DataTables generated nodes, events and classes */ |
515
|
|
|
oSettings.nTable.parentNode.removeChild( oSettings.nTable ); |
516
|
|
|
$(oSettings.nTableWrapper).remove(); |
517
|
|
|
|
518
|
|
|
oSettings.aaSorting = []; |
519
|
|
|
oSettings.aaSortingFixed = []; |
520
|
|
|
_fnSortingClasses( oSettings ); |
521
|
|
|
|
522
|
|
|
$(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') ); |
523
|
|
|
|
524
|
|
|
$('th, td', oSettings.nTHead).removeClass( [ |
525
|
|
|
oSettings.oClasses.sSortable, |
526
|
|
|
oSettings.oClasses.sSortableAsc, |
527
|
|
|
oSettings.oClasses.sSortableDesc, |
528
|
|
|
oSettings.oClasses.sSortableNone ].join(' ') |
529
|
|
|
); |
530
|
|
|
if ( oSettings.bJUI ) |
531
|
|
|
{ |
532
|
|
|
$('th span.'+oSettings.oClasses.sSortIcon |
533
|
|
|
+ ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove(); |
534
|
|
|
|
535
|
|
|
$('th, td', oSettings.nTHead).each( function () { |
536
|
|
|
var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this); |
537
|
|
|
var kids = jqWrapper.contents(); |
538
|
|
|
$(this).append( kids ); |
539
|
|
|
jqWrapper.remove(); |
540
|
|
|
} ); |
541
|
|
|
} |
542
|
|
|
|
543
|
|
|
/* Add the TR elements back into the table in their original order */ |
544
|
|
|
if ( !bRemove && oSettings.nTableReinsertBefore ) |
545
|
|
|
{ |
546
|
|
|
nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore ); |
547
|
|
|
} |
548
|
|
|
else if ( !bRemove ) |
549
|
|
|
{ |
550
|
|
|
nOrig.appendChild( oSettings.nTable ); |
551
|
|
|
} |
552
|
|
|
|
553
|
|
|
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) |
554
|
|
|
{ |
555
|
|
|
if ( oSettings.aoData[i].nTr !== null ) |
556
|
|
|
{ |
557
|
|
|
nBody.appendChild( oSettings.aoData[i].nTr ); |
558
|
|
|
} |
559
|
|
|
} |
560
|
|
|
|
561
|
|
|
/* Restore the width of the original table */ |
562
|
|
|
if ( oSettings.oFeatures.bAutoWidth === true ) |
563
|
|
|
{ |
564
|
|
|
oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth); |
565
|
|
|
} |
566
|
|
|
|
567
|
|
|
/* If the were originally stripe classes - then we add them back here. Note |
568
|
|
|
* this is not fool proof (for example if not all rows had stripe classes - but |
569
|
|
|
* it's a good effort without getting carried away |
570
|
|
|
*/ |
571
|
|
|
iLen = oSettings.asDestroyStripes.length; |
572
|
|
|
if (iLen) |
573
|
|
|
{ |
574
|
|
|
var anRows = $(nBody).children('tr'); |
575
|
|
|
for ( i=0 ; i<iLen ; i++ ) |
576
|
|
|
{ |
577
|
|
|
anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] ); |
578
|
|
|
} |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
/* Remove the settings object from the settings array */ |
582
|
|
|
for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ ) |
583
|
|
|
{ |
584
|
|
|
if ( DataTable.settings[i] == oSettings ) |
585
|
|
|
{ |
586
|
|
|
DataTable.settings.splice( i, 1 ); |
587
|
|
|
} |
588
|
|
|
} |
589
|
|
|
|
590
|
|
|
/* End it all */ |
591
|
|
|
oSettings = null; |
|
|
|
|
592
|
|
|
oInit = null; |
|
|
|
|
593
|
|
|
}; |
594
|
|
|
|
595
|
|
|
|
596
|
|
|
/** |
597
|
|
|
* Redraw the table |
598
|
|
|
* @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw. |
599
|
|
|
* @dtopt API |
600
|
|
|
* |
601
|
|
|
* @example |
602
|
|
|
* $(document).ready(function() { |
603
|
|
|
* var oTable = $('#example').dataTable(); |
604
|
|
|
* |
605
|
|
|
* // Re-draw the table - you wouldn't want to do it here, but it's an example :-) |
606
|
|
|
* oTable.fnDraw(); |
607
|
|
|
* } ); |
608
|
|
|
*/ |
609
|
|
|
this.fnDraw = function( bComplete ) |
610
|
|
|
{ |
611
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
612
|
|
|
if ( bComplete === false ) |
613
|
|
|
{ |
614
|
|
|
_fnCalculateEnd( oSettings ); |
615
|
|
|
_fnDraw( oSettings ); |
616
|
|
|
} |
617
|
|
|
else |
618
|
|
|
{ |
619
|
|
|
_fnReDraw( oSettings ); |
620
|
|
|
} |
621
|
|
|
}; |
622
|
|
|
|
623
|
|
|
|
624
|
|
|
/** |
625
|
|
|
* Filter the input based on data |
626
|
|
|
* @param {string} sInput String to filter the table on |
627
|
|
|
* @param {int|null} [iColumn] Column to limit filtering to |
628
|
|
|
* @param {bool} [bRegex=false] Treat as regular expression or not |
629
|
|
|
* @param {bool} [bSmart=true] Perform smart filtering or not |
630
|
|
|
* @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) |
631
|
|
|
* @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) |
632
|
|
|
* @dtopt API |
633
|
|
|
* |
634
|
|
|
* @example |
635
|
|
|
* $(document).ready(function() { |
636
|
|
|
* var oTable = $('#example').dataTable(); |
637
|
|
|
* |
638
|
|
|
* // Sometime later - filter... |
639
|
|
|
* oTable.fnFilter( 'test string' ); |
640
|
|
|
* } ); |
641
|
|
|
*/ |
642
|
|
|
this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) |
643
|
|
|
{ |
644
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
645
|
|
|
|
646
|
|
|
if ( !oSettings.oFeatures.bFilter ) |
647
|
|
|
{ |
648
|
|
|
return; |
649
|
|
|
} |
650
|
|
|
|
651
|
|
|
if ( bRegex === undefined || bRegex === null ) |
652
|
|
|
{ |
653
|
|
|
bRegex = false; |
654
|
|
|
} |
655
|
|
|
|
656
|
|
|
if ( bSmart === undefined || bSmart === null ) |
657
|
|
|
{ |
658
|
|
|
bSmart = true; |
659
|
|
|
} |
660
|
|
|
|
661
|
|
|
if ( bShowGlobal === undefined || bShowGlobal === null ) |
662
|
|
|
{ |
663
|
|
|
bShowGlobal = true; |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
if ( bCaseInsensitive === undefined || bCaseInsensitive === null ) |
667
|
|
|
{ |
668
|
|
|
bCaseInsensitive = true; |
669
|
|
|
} |
670
|
|
|
|
671
|
|
|
if ( iColumn === undefined || iColumn === null ) |
672
|
|
|
{ |
673
|
|
|
/* Global filter */ |
674
|
|
|
_fnFilterComplete( oSettings, { |
675
|
|
|
"sSearch":sInput+"", |
676
|
|
|
"bRegex": bRegex, |
677
|
|
|
"bSmart": bSmart, |
678
|
|
|
"bCaseInsensitive": bCaseInsensitive |
679
|
|
|
}, 1 ); |
680
|
|
|
|
681
|
|
|
if ( bShowGlobal && oSettings.aanFeatures.f ) |
682
|
|
|
{ |
683
|
|
|
var n = oSettings.aanFeatures.f; |
684
|
|
|
for ( var i=0, iLen=n.length ; i<iLen ; i++ ) |
685
|
|
|
{ |
686
|
|
|
// IE9 throws an 'unknown error' if document.AktifElement is used |
687
|
|
|
// inside an iframe or frame... |
688
|
|
|
try { |
689
|
|
|
if ( n[i]._DT_Input != document.AktifElement ) |
690
|
|
|
{ |
691
|
|
|
$(n[i]._DT_Input).val( sInput ); |
692
|
|
|
} |
693
|
|
|
} |
694
|
|
|
catch ( e ) { |
695
|
|
|
$(n[i]._DT_Input).val( sInput ); |
696
|
|
|
} |
697
|
|
|
} |
698
|
|
|
} |
699
|
|
|
} |
700
|
|
|
else |
701
|
|
|
{ |
702
|
|
|
/* Single column filter */ |
703
|
|
|
$.extend( oSettings.aoPreSearchCols[ iColumn ], { |
704
|
|
|
"sSearch": sInput+"", |
705
|
|
|
"bRegex": bRegex, |
706
|
|
|
"bSmart": bSmart, |
707
|
|
|
"bCaseInsensitive": bCaseInsensitive |
708
|
|
|
} ); |
709
|
|
|
_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 ); |
710
|
|
|
} |
711
|
|
|
}; |
712
|
|
|
|
713
|
|
|
|
714
|
|
|
/** |
715
|
|
|
* Get the data for the whole table, an individual row or an individual cell based on the |
716
|
|
|
* provided parameters. |
717
|
|
|
* @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as |
718
|
|
|
* a TR node then the data source for the whole row will be returned. If given as a |
719
|
|
|
* TD/TH cell node then iCol will be automatically calculated and the data for the |
720
|
|
|
* cell returned. If given as an integer, then this is treated as the aoData internal |
721
|
|
|
* data index for the row (see fnGetPosition) and the data for that row used. |
722
|
|
|
* @param {int} [iCol] Optional column index that you want the data of. |
723
|
|
|
* @returns {array|object|string} If mRow is undefined, then the data for all rows is |
724
|
|
|
* returned. If mRow is defined, just data for that row, and is iCol is |
725
|
|
|
* defined, only data for the designated cell is returned. |
726
|
|
|
* @dtopt API |
727
|
|
|
* |
728
|
|
|
* @example |
729
|
|
|
* // Row data |
730
|
|
|
* $(document).ready(function() { |
731
|
|
|
* oTable = $('#example').dataTable(); |
732
|
|
|
* |
733
|
|
|
* oTable.$('tr').click( function () { |
734
|
|
|
* var data = oTable.fnGetData( this ); |
735
|
|
|
* // ... do something with the array / object of data for the row |
736
|
|
|
* } ); |
737
|
|
|
* } ); |
738
|
|
|
* |
739
|
|
|
* @example |
740
|
|
|
* // Individual cell data |
741
|
|
|
* $(document).ready(function() { |
742
|
|
|
* oTable = $('#example').dataTable(); |
743
|
|
|
* |
744
|
|
|
* oTable.$('td').click( function () { |
745
|
|
|
* var sData = oTable.fnGetData( this ); |
746
|
|
|
* alert( 'The cell clicked on had the value of '+sData ); |
747
|
|
|
* } ); |
748
|
|
|
* } ); |
749
|
|
|
*/ |
750
|
|
|
this.fnGetData = function( mRow, iCol ) |
751
|
|
|
{ |
752
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
753
|
|
|
|
754
|
|
|
if ( mRow !== undefined ) |
755
|
|
|
{ |
756
|
|
|
var iRow = mRow; |
757
|
|
|
if ( typeof mRow === 'object' ) |
758
|
|
|
{ |
759
|
|
|
var sNode = mRow.nodeName.toLowerCase(); |
760
|
|
|
if (sNode === "tr" ) |
761
|
|
|
{ |
762
|
|
|
iRow = _fnNodeToDataIndex(oSettings, mRow); |
763
|
|
|
} |
764
|
|
|
else if ( sNode === "td" ) |
765
|
|
|
{ |
766
|
|
|
iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode); |
767
|
|
|
iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow ); |
768
|
|
|
} |
769
|
|
|
} |
770
|
|
|
|
771
|
|
|
if ( iCol !== undefined ) |
772
|
|
|
{ |
773
|
|
|
return _fnGetCellData( oSettings, iRow, iCol, '' ); |
774
|
|
|
} |
775
|
|
|
return (oSettings.aoData[iRow]!==undefined) ? |
776
|
|
|
oSettings.aoData[iRow]._aData : null; |
777
|
|
|
} |
778
|
|
|
return _fnGetDataMaster( oSettings ); |
779
|
|
|
}; |
780
|
|
|
|
781
|
|
|
|
782
|
|
|
/** |
783
|
|
|
* Get an array of the TR nodes that are used in the table's body. Note that you will |
784
|
|
|
* typically want to use the '$' API method in preference to this as it is more |
785
|
|
|
* flexible. |
786
|
|
|
* @param {int} [iRow] Optional row index for the TR element you want |
787
|
|
|
* @returns {array|node} If iRow is undefined, returns an array of all TR elements |
788
|
|
|
* in the table's body, or iRow is defined, just the TR element requested. |
789
|
|
|
* @dtopt API |
790
|
|
|
* |
791
|
|
|
* @example |
792
|
|
|
* $(document).ready(function() { |
793
|
|
|
* var oTable = $('#example').dataTable(); |
794
|
|
|
* |
795
|
|
|
* // Get the nodes from the table |
796
|
|
|
* var nNodes = oTable.fnGetNodes( ); |
797
|
|
|
* } ); |
798
|
|
|
*/ |
799
|
|
|
this.fnGetNodes = function( iRow ) |
800
|
|
|
{ |
801
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
802
|
|
|
|
803
|
|
|
if ( iRow !== undefined ) { |
804
|
|
|
return (oSettings.aoData[iRow]!==undefined) ? |
805
|
|
|
oSettings.aoData[iRow].nTr : null; |
806
|
|
|
} |
807
|
|
|
return _fnGetTrNodes( oSettings ); |
808
|
|
|
}; |
809
|
|
|
|
810
|
|
|
|
811
|
|
|
/** |
812
|
|
|
* Get the array indexes of a particular cell from it's DOM element |
813
|
|
|
* and column index including hidden columns |
814
|
|
|
* @param {node} nNode this can either be a TR, TD or TH in the table's body |
815
|
|
|
* @returns {int} If nNode is given as a TR, then a single index is returned, or |
816
|
|
|
* if given as a cell, an array of [row index, column index (visible), |
817
|
|
|
* column index (all)] is given. |
818
|
|
|
* @dtopt API |
819
|
|
|
* |
820
|
|
|
* @example |
821
|
|
|
* $(document).ready(function() { |
822
|
|
|
* $('#example tbody td').click( function () { |
823
|
|
|
* // Get the position of the current data from the node |
824
|
|
|
* var aPos = oTable.fnGetPosition( this ); |
825
|
|
|
* |
826
|
|
|
* // Get the data array for this row |
827
|
|
|
* var aData = oTable.fnGetData( aPos[0] ); |
828
|
|
|
* |
829
|
|
|
* // Update the data array and return the value |
830
|
|
|
* aData[ aPos[1] ] = 'clicked'; |
831
|
|
|
* this.innerHTML = 'clicked'; |
832
|
|
|
* } ); |
833
|
|
|
* |
834
|
|
|
* // Init DataTables |
835
|
|
|
* oTable = $('#example').dataTable(); |
836
|
|
|
* } ); |
837
|
|
|
*/ |
838
|
|
|
this.fnGetPosition = function( nNode ) |
839
|
|
|
{ |
840
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
841
|
|
|
var sNodeName = nNode.nodeName.toUpperCase(); |
842
|
|
|
|
843
|
|
|
if ( sNodeName == "TR" ) |
844
|
|
|
{ |
845
|
|
|
return _fnNodeToDataIndex(oSettings, nNode); |
846
|
|
|
} |
847
|
|
|
else if ( sNodeName == "TD" || sNodeName == "TH" ) |
848
|
|
|
{ |
849
|
|
|
var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode ); |
850
|
|
|
var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode ); |
851
|
|
|
return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ]; |
852
|
|
|
} |
853
|
|
|
return null; |
854
|
|
|
}; |
855
|
|
|
|
856
|
|
|
|
857
|
|
|
/** |
858
|
|
|
* Check to see if a row is 'open' or not. |
859
|
|
|
* @param {node} nTr the table row to check |
860
|
|
|
* @returns {boolean} true if the row is currently open, false otherwise |
861
|
|
|
* @dtopt API |
862
|
|
|
* |
863
|
|
|
* @example |
864
|
|
|
* $(document).ready(function() { |
865
|
|
|
* var oTable; |
866
|
|
|
* |
867
|
|
|
* // 'open' an information row when a row is clicked on |
868
|
|
|
* $('#example tbody tr').click( function () { |
869
|
|
|
* if ( oTable.fnIsOpen(this) ) { |
870
|
|
|
* oTable.fnClose( this ); |
871
|
|
|
* } else { |
872
|
|
|
* oTable.fnOpen( this, "Temporary row opened", "info_row" ); |
873
|
|
|
* } |
874
|
|
|
* } ); |
875
|
|
|
* |
876
|
|
|
* oTable = $('#example').dataTable(); |
877
|
|
|
* } ); |
878
|
|
|
*/ |
879
|
|
|
this.fnIsOpen = function( nTr ) |
880
|
|
|
{ |
881
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
882
|
|
|
var aoOpenRows = oSettings.aoOpenRows; |
883
|
|
|
|
884
|
|
|
for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ ) |
885
|
|
|
{ |
886
|
|
|
if ( oSettings.aoOpenRows[i].nParent == nTr ) |
887
|
|
|
{ |
888
|
|
|
return true; |
889
|
|
|
} |
890
|
|
|
} |
891
|
|
|
return false; |
892
|
|
|
}; |
893
|
|
|
|
894
|
|
|
|
895
|
|
|
/** |
896
|
|
|
* This function will place a new row directly after a row which is currently |
897
|
|
|
* on display on the page, with the HTML contents that is passed into the |
898
|
|
|
* function. This can be used, for example, to ask for confirmation that a |
899
|
|
|
* particular record should be deleted. |
900
|
|
|
* @param {node} nTr The table row to 'open' |
901
|
|
|
* @param {string|node|jQuery} mHtml The HTML to put into the row |
902
|
|
|
* @param {string} sClass Class to give the new TD cell |
903
|
|
|
* @returns {node} The row opened. Note that if the table row passed in as the |
904
|
|
|
* first parameter, is not found in the table, this method will silently |
905
|
|
|
* return. |
906
|
|
|
* @dtopt API |
907
|
|
|
* |
908
|
|
|
* @example |
909
|
|
|
* $(document).ready(function() { |
910
|
|
|
* var oTable; |
911
|
|
|
* |
912
|
|
|
* // 'open' an information row when a row is clicked on |
913
|
|
|
* $('#example tbody tr').click( function () { |
914
|
|
|
* if ( oTable.fnIsOpen(this) ) { |
915
|
|
|
* oTable.fnClose( this ); |
916
|
|
|
* } else { |
917
|
|
|
* oTable.fnOpen( this, "Temporary row opened", "info_row" ); |
918
|
|
|
* } |
919
|
|
|
* } ); |
920
|
|
|
* |
921
|
|
|
* oTable = $('#example').dataTable(); |
922
|
|
|
* } ); |
923
|
|
|
*/ |
924
|
|
|
this.fnOpen = function( nTr, mHtml, sClass ) |
925
|
|
|
{ |
926
|
|
|
/* Find settings from table node */ |
927
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
928
|
|
|
|
929
|
|
|
/* Check that the row given is in the table */ |
930
|
|
|
var nTableRows = _fnGetTrNodes( oSettings ); |
931
|
|
|
if ( $.inArray(nTr, nTableRows) === -1 ) |
932
|
|
|
{ |
933
|
|
|
return; |
|
|
|
|
934
|
|
|
} |
935
|
|
|
|
936
|
|
|
/* the old open one if there is one */ |
937
|
|
|
this.fnClose( nTr ); |
938
|
|
|
|
939
|
|
|
var nNewRow = document.createElement("tr"); |
940
|
|
|
var nNewCell = document.createElement("td"); |
941
|
|
|
nNewRow.appendChild( nNewCell ); |
942
|
|
|
nNewCell.className = sClass; |
943
|
|
|
nNewCell.colSpan = _fnVisbleColumns( oSettings ); |
944
|
|
|
|
945
|
|
|
if (typeof mHtml === "string") |
946
|
|
|
{ |
947
|
|
|
nNewCell.innerHTML = mHtml; |
948
|
|
|
} |
949
|
|
|
else |
950
|
|
|
{ |
951
|
|
|
$(nNewCell).html( mHtml ); |
952
|
|
|
} |
953
|
|
|
|
954
|
|
|
/* If the nTr isn't on the page at the moment - then we don't insert at the moment */ |
955
|
|
|
var nTrs = $('tr', oSettings.nTBody); |
956
|
|
|
if ( $.inArray(nTr, nTrs) != -1 ) |
957
|
|
|
{ |
958
|
|
|
$(nNewRow).insertAfter(nTr); |
959
|
|
|
} |
960
|
|
|
|
961
|
|
|
oSettings.aoOpenRows.push( { |
962
|
|
|
"nTr": nNewRow, |
963
|
|
|
"nParent": nTr |
964
|
|
|
} ); |
965
|
|
|
|
966
|
|
|
return nNewRow; |
967
|
|
|
}; |
968
|
|
|
|
969
|
|
|
|
970
|
|
|
/** |
971
|
|
|
* Change the pagination - provides the internal logic for pagination in a simple API |
972
|
|
|
* function. With this function you can have a DataTables table go to the next, |
973
|
|
|
* previous, first or last pages. |
974
|
|
|
* @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" |
975
|
|
|
* or page number to jump to (integer), note that page 0 is the first page. |
976
|
|
|
* @param {bool} [bRedraw=true] Redraw the table or not |
977
|
|
|
* @dtopt API |
978
|
|
|
* |
979
|
|
|
* @example |
980
|
|
|
* $(document).ready(function() { |
981
|
|
|
* var oTable = $('#example').dataTable(); |
982
|
|
|
* oTable.fnPageChange( 'next' ); |
983
|
|
|
* } ); |
984
|
|
|
*/ |
985
|
|
|
this.fnPageChange = function ( mAction, bRedraw ) |
986
|
|
|
{ |
987
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
988
|
|
|
_fnPageChange( oSettings, mAction ); |
989
|
|
|
_fnCalculateEnd( oSettings ); |
990
|
|
|
|
991
|
|
|
if ( bRedraw === undefined || bRedraw ) |
992
|
|
|
{ |
993
|
|
|
_fnDraw( oSettings ); |
994
|
|
|
} |
995
|
|
|
}; |
996
|
|
|
|
997
|
|
|
|
998
|
|
|
/** |
999
|
|
|
* Show a particular column |
1000
|
|
|
* @param {int} iCol The column whose display should be changed |
1001
|
|
|
* @param {bool} bShow Show (true) or hide (false) the column |
1002
|
|
|
* @param {bool} [bRedraw=true] Redraw the table or not |
1003
|
|
|
* @dtopt API |
1004
|
|
|
* |
1005
|
|
|
* @example |
1006
|
|
|
* $(document).ready(function() { |
1007
|
|
|
* var oTable = $('#example').dataTable(); |
1008
|
|
|
* |
1009
|
|
|
* // Hide the second column after initialisation |
1010
|
|
|
* oTable.fnSetColumnVis( 1, false ); |
1011
|
|
|
* } ); |
1012
|
|
|
*/ |
1013
|
|
|
this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) |
1014
|
|
|
{ |
1015
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
1016
|
|
|
var i, iLen; |
1017
|
|
|
var aoColumns = oSettings.aoColumns; |
1018
|
|
|
var aoData = oSettings.aoData; |
1019
|
|
|
var nTd, bAppend, iBefore; |
1020
|
|
|
|
1021
|
|
|
/* No point in doing anything if we are requesting what is already true */ |
1022
|
|
|
if ( aoColumns[iCol].bVisible == bShow ) |
1023
|
|
|
{ |
1024
|
|
|
return; |
1025
|
|
|
} |
1026
|
|
|
|
1027
|
|
|
/* Show the column */ |
1028
|
|
|
if ( bShow ) |
1029
|
|
|
{ |
1030
|
|
|
var iInsert = 0; |
1031
|
|
|
for ( i=0 ; i<iCol ; i++ ) |
1032
|
|
|
{ |
1033
|
|
|
if ( aoColumns[i].bVisible ) |
1034
|
|
|
{ |
1035
|
|
|
iInsert++; |
1036
|
|
|
} |
1037
|
|
|
} |
1038
|
|
|
|
1039
|
|
|
/* Need to decide if we should use appendChild or insertBefore */ |
1040
|
|
|
bAppend = (iInsert >= _fnVisbleColumns( oSettings )); |
1041
|
|
|
|
1042
|
|
|
/* Which coloumn should we be inserting before? */ |
1043
|
|
|
if ( !bAppend ) |
1044
|
|
|
{ |
1045
|
|
|
for ( i=iCol ; i<aoColumns.length ; i++ ) |
1046
|
|
|
{ |
1047
|
|
|
if ( aoColumns[i].bVisible ) |
1048
|
|
|
{ |
1049
|
|
|
iBefore = i; |
1050
|
|
|
break; |
1051
|
|
|
} |
1052
|
|
|
} |
1053
|
|
|
} |
1054
|
|
|
|
1055
|
|
|
for ( i=0, iLen=aoData.length ; i<iLen ; i++ ) |
1056
|
|
|
{ |
1057
|
|
|
if ( aoData[i].nTr !== null ) |
1058
|
|
|
{ |
1059
|
|
|
if ( bAppend ) |
1060
|
|
|
{ |
1061
|
|
|
aoData[i].nTr.appendChild( |
1062
|
|
|
aoData[i]._anHidden[iCol] |
1063
|
|
|
); |
1064
|
|
|
} |
1065
|
|
|
else |
1066
|
|
|
{ |
1067
|
|
|
aoData[i].nTr.insertBefore( |
1068
|
|
|
aoData[i]._anHidden[iCol], |
1069
|
|
|
_fnGetTdNodes( oSettings, i )[iBefore] ); |
|
|
|
|
1070
|
|
|
} |
1071
|
|
|
} |
1072
|
|
|
} |
1073
|
|
|
} |
1074
|
|
|
else |
1075
|
|
|
{ |
1076
|
|
|
/* Remove a column from display */ |
1077
|
|
|
for ( i=0, iLen=aoData.length ; i<iLen ; i++ ) |
1078
|
|
|
{ |
1079
|
|
|
if ( aoData[i].nTr !== null ) |
1080
|
|
|
{ |
1081
|
|
|
nTd = _fnGetTdNodes( oSettings, i )[iCol]; |
1082
|
|
|
aoData[i]._anHidden[iCol] = nTd; |
1083
|
|
|
nTd.parentNode.removeChild( nTd ); |
1084
|
|
|
} |
1085
|
|
|
} |
1086
|
|
|
} |
1087
|
|
|
|
1088
|
|
|
/* Clear to set the visible flag */ |
1089
|
|
|
aoColumns[iCol].bVisible = bShow; |
1090
|
|
|
|
1091
|
|
|
/* Redraw the header and footer based on the new column visibility */ |
1092
|
|
|
_fnDrawHead( oSettings, oSettings.aoHeader ); |
1093
|
|
|
if ( oSettings.nTFoot ) |
1094
|
|
|
{ |
1095
|
|
|
_fnDrawHead( oSettings, oSettings.aoFooter ); |
1096
|
|
|
} |
1097
|
|
|
|
1098
|
|
|
/* If there are any 'open' rows, then we need to alter the colspan for this col change */ |
1099
|
|
|
for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ ) |
1100
|
|
|
{ |
1101
|
|
|
oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings ); |
1102
|
|
|
} |
1103
|
|
|
|
1104
|
|
|
/* Do a redraw incase anything depending on the table columns needs it |
1105
|
|
|
* (built-in: scrolling) |
1106
|
|
|
*/ |
1107
|
|
|
if ( bRedraw === undefined || bRedraw ) |
1108
|
|
|
{ |
1109
|
|
|
_fnAdjustColumnSizing( oSettings ); |
1110
|
|
|
_fnDraw( oSettings ); |
1111
|
|
|
} |
1112
|
|
|
|
1113
|
|
|
_fnSaveState( oSettings ); |
1114
|
|
|
}; |
1115
|
|
|
|
1116
|
|
|
|
1117
|
|
|
/** |
1118
|
|
|
* Get the settings for a particular table for external manipulation |
1119
|
|
|
* @returns {object} DataTables settings object. See |
1120
|
|
|
* {@link DataTable.models.oSettings} |
1121
|
|
|
* @dtopt API |
1122
|
|
|
* |
1123
|
|
|
* @example |
1124
|
|
|
* $(document).ready(function() { |
1125
|
|
|
* var oTable = $('#example').dataTable(); |
1126
|
|
|
* var oSettings = oTable.fnSettings(); |
1127
|
|
|
* |
1128
|
|
|
* // Show an example parameter from the settings |
1129
|
|
|
* alert( oSettings._iDisplayStart ); |
1130
|
|
|
* } ); |
1131
|
|
|
*/ |
1132
|
|
|
this.fnSettings = function() |
1133
|
|
|
{ |
1134
|
|
|
return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
1135
|
|
|
}; |
1136
|
|
|
|
1137
|
|
|
|
1138
|
|
|
/** |
1139
|
|
|
* Sort the table by a particular column |
1140
|
|
|
* @param {int} iCol the data index to sort on. Note that this will not match the |
1141
|
|
|
* 'display index' if you have hidden data entries |
1142
|
|
|
* @dtopt API |
1143
|
|
|
* |
1144
|
|
|
* @example |
1145
|
|
|
* $(document).ready(function() { |
1146
|
|
|
* var oTable = $('#example').dataTable(); |
1147
|
|
|
* |
1148
|
|
|
* // Sort immediately with columns 0 and 1 |
1149
|
|
|
* oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); |
1150
|
|
|
* } ); |
1151
|
|
|
*/ |
1152
|
|
|
this.fnSort = function( aaSort ) |
1153
|
|
|
{ |
1154
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
1155
|
|
|
oSettings.aaSorting = aaSort; |
1156
|
|
|
_fnSort( oSettings ); |
1157
|
|
|
}; |
1158
|
|
|
|
1159
|
|
|
|
1160
|
|
|
/** |
1161
|
|
|
* Attach a sort listener to an element for a given column |
1162
|
|
|
* @param {node} nNode the element to attach the sort listener to |
1163
|
|
|
* @param {int} iColumn the column that a click on this node will sort on |
1164
|
|
|
* @param {function} [fnCallback] callback function when sort is run |
1165
|
|
|
* @dtopt API |
1166
|
|
|
* |
1167
|
|
|
* @example |
1168
|
|
|
* $(document).ready(function() { |
1169
|
|
|
* var oTable = $('#example').dataTable(); |
1170
|
|
|
* |
1171
|
|
|
* // Sort on column 1, when 'sorter' is clicked on |
1172
|
|
|
* oTable.fnSortListener( document.getElementById('sorter'), 1 ); |
1173
|
|
|
* } ); |
1174
|
|
|
*/ |
1175
|
|
|
this.fnSortListener = function( nNode, iColumn, fnCallback ) |
1176
|
|
|
{ |
1177
|
|
|
_fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn, |
1178
|
|
|
fnCallback ); |
1179
|
|
|
}; |
1180
|
|
|
|
1181
|
|
|
|
1182
|
|
|
/** |
1183
|
|
|
* Update a table cell or row - this method will accept either a single value to |
1184
|
|
|
* update the cell with, an array of values with one element for each column or |
1185
|
|
|
* an object in the same format as the original data source. The function is |
1186
|
|
|
* self-referencing in order to make the multi column updates easier. |
1187
|
|
|
* @param {object|array|string} mData Data to update the cell/row with |
1188
|
|
|
* @param {node|int} mRow TR element you want to update or the aoData index |
1189
|
|
|
* @param {int} [iColumn] The column to update, give as null or undefined to |
1190
|
|
|
* update a whole row. |
1191
|
|
|
* @param {bool} [bRedraw=true] Redraw the table or not |
1192
|
|
|
* @param {bool} [bAction=true] Perform pre-draw actions or not |
1193
|
|
|
* @returns {int} 0 on success, 1 on error |
1194
|
|
|
* @dtopt API |
1195
|
|
|
* |
1196
|
|
|
* @example |
1197
|
|
|
* $(document).ready(function() { |
1198
|
|
|
* var oTable = $('#example').dataTable(); |
1199
|
|
|
* oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell |
1200
|
|
|
* oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row |
1201
|
|
|
* } ); |
1202
|
|
|
*/ |
1203
|
|
|
this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) |
1204
|
|
|
{ |
1205
|
|
|
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); |
1206
|
|
|
var i, sDisplay; |
1207
|
|
|
var iRow = (typeof mRow === 'object') ? |
1208
|
|
|
_fnNodeToDataIndex(oSettings, mRow) : mRow; |
1209
|
|
|
|
1210
|
|
|
if ( iColumn === undefined || iColumn === null ) |
1211
|
|
|
{ |
1212
|
|
|
/* Update the whole row */ |
1213
|
|
|
oSettings.aoData[iRow]._aData = mData; |
1214
|
|
|
|
1215
|
|
|
for ( i=0 ; i<oSettings.aoColumns.length ; i++ ) |
1216
|
|
|
{ |
1217
|
|
|
this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false ); |
1218
|
|
|
} |
1219
|
|
|
} |
1220
|
|
|
else |
1221
|
|
|
{ |
1222
|
|
|
/* Individual cell update */ |
1223
|
|
|
_fnSetCellData( oSettings, iRow, iColumn, mData ); |
1224
|
|
|
sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' ); |
1225
|
|
|
|
1226
|
|
|
var oCol = oSettings.aoColumns[iColumn]; |
|
|
|
|
1227
|
|
|
if ( oSettings.aoData[iRow].nTr !== null ) |
1228
|
|
|
{ |
1229
|
|
|
/* Do the actual HTML update */ |
1230
|
|
|
_fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay; |
1231
|
|
|
} |
1232
|
|
|
} |
1233
|
|
|
|
1234
|
|
|
/* Modify the search index for this row (strictly this is likely not needed, since fnReDraw |
1235
|
|
|
* will rebuild the search array - however, the redraw might be disabled by the user) |
1236
|
|
|
*/ |
1237
|
|
|
var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay ); |
1238
|
|
|
oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow( |
1239
|
|
|
oSettings, |
1240
|
|
|
_fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) ) |
1241
|
|
|
); |
1242
|
|
|
|
1243
|
|
|
/* Perform pre-draw actions */ |
1244
|
|
|
if ( bAction === undefined || bAction ) |
1245
|
|
|
{ |
1246
|
|
|
_fnAdjustColumnSizing( oSettings ); |
1247
|
|
|
} |
1248
|
|
|
|
1249
|
|
|
/* Redraw the table */ |
1250
|
|
|
if ( bRedraw === undefined || bRedraw ) |
1251
|
|
|
{ |
1252
|
|
|
_fnReDraw( oSettings ); |
1253
|
|
|
} |
1254
|
|
|
return 0; |
1255
|
|
|
}; |
1256
|
|
|
|
1257
|
|
|
|
1258
|
|
|
/** |
1259
|
|
|
* Provide a common method for plug-ins to check the version of DataTables being used, in order |
1260
|
|
|
* to ensure compatibility. |
1261
|
|
|
* @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the |
1262
|
|
|
* formats "X" and "X.Y" are also acceptable. |
1263
|
|
|
* @returns {boolean} true if this version of DataTables is greater or equal to the required |
1264
|
|
|
* version, or false if this version of DataTales is not suitable |
1265
|
|
|
* @method |
1266
|
|
|
* @dtopt API |
1267
|
|
|
* |
1268
|
|
|
* @example |
1269
|
|
|
* $(document).ready(function() { |
1270
|
|
|
* var oTable = $('#example').dataTable(); |
1271
|
|
|
* alert( oTable.fnVersionCheck( '1.9.0' ) ); |
1272
|
|
|
* } ); |
1273
|
|
|
*/ |
1274
|
|
|
this.fnVersionCheck = DataTable.ext.fnVersionCheck; |
1275
|
|
|
|
1276
|
|
|
|